use serde::{Serialize, Deserialize};
use serde_json;
use crypto::{sha2::Sha256, digest::Digest};
use chrono::{Utc, Duration};
use std::{iter::repeat, ops::Add};

use rsa::{ RsaPrivateKey, PaddingScheme, pkcs1::FromRsaPrivateKey, Hash};

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Header {
    alg: String,
    kid: String,
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct RsaKey <'a> {
    pub_key: &'a str,
    pri_key: &'a str,
}

fn get_rsa_key() -> RsaKey<'static>{
    let rsa_key = RsaKey {
        pub_key: r#"
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAju1AroJg+uOH6M7zJzg7
tNI5bzTkEFvcyMhomgNFrMgB4uRcw1KG2u0QGr3JypklvWpQkIpEDyKwkGbs8zQb
PUwWZ0bxVsejceadANvRkXKivA5OI2CkUIvYYmNLwrDljw8FgAtlkWYqsntyi7dJ
VC0NaxHGk15ERdDfq8R0wFLTIXNQfNcoRBOU4QONY3V9CwwxYdb4OQlWE3yo2wK6
y7NsqF4YKRmdB3MVxIyfBznXkT6B3xdojWm2WE220vxIkd2xGNKalunMqS7J2G59
OSgX9YqFTCphthZ8shFGP/t+gHqWQMyalUwu/+TgVzeRRUVokxbea91OjbuE54RE
FQIBAw==
-----END PUBLIC KEY-----"#,
        pri_key: r#"
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAju1AroJg+uOH6M7zJzg7tNI5bzTkEFvcyMhomgNFrMgB4uRc
w1KG2u0QGr3JypklvWpQkIpEDyKwkGbs8zQbPUwWZ0bxVsejceadANvRkXKivA5O
I2CkUIvYYmNLwrDljw8FgAtlkWYqsntyi7dJVC0NaxHGk15ERdDfq8R0wFLTIXNQ
fNcoRBOU4QONY3V9CwwxYdb4OQlWE3yo2wK6y7NsqF4YKRmdB3MVxIyfBznXkT6B
3xdojWm2WE220vxIkd2xGNKalunMqS7J2G59OSgX9YqFTCphthZ8shFGP/t+gHqW
QMyalUwu/+TgVzeRRUVokxbea91OjbuE54REFQIBAwKCAQAX0jVyaxAp0JamzSiG
iV9IzbQ9M3tYD092zBFvAIuczABQe2TLOGvPJ4KvH6GhxDD05w1tbGCtMHLCu9Io
iK804gO74Sg5IUXoURoqz02YPcXKAmJbOsYNbKQQZeH1yCZCgoDqrJDtkQcdvz3B
8+GOB4I8gvZt5Qtg+CVHS2jKuDfpOo54jRAahGQfXQnH02ySSRW2AvQFbAVAuvEg
IcB4hBBOZVQz7APpLCaMwRbbTJFw1n9e/Co2TjIXU2Tt4ba49idaG5ZRq2Z2bW/s
U9idKe2SA6cI0a/q8wNgE66IvbG5JkZUojdI8+p9Pwdy+4XVUrkmTOg5W3G3Mee5
d0ZtAoGBAOEp5wdHtdZvqwbQnLjOGVqoKp6WGLHCLC4TFJTf5SyiK2VaN1oc+BDf
u1EJiM1rL3WFVfdyTgPMzIOWV2uJxHcDvx2ea/CYdebkmaWnskyzhJ/Bmd7clnPF
rgVnXDj3u7c6GjA+wE6HbZRHmYtF23EyoFJtPu+VXxdufufycAfjAoGBAKKALPJh
0vE1TjVUOJnmZ5b1KxCHrI5WVQh8Bm06UwtWb6V3xsTUmXSwrt1ufUh4Pvlm4Y4y
4Gd6yAY2Ae217Yk4WaddwSQUb37+BISmxRzWp+bH2rw6qc5utmMKPvYTzZzvesAG
PwBYJxvI0Shfdv0StL9ACn1+WYzUES6cSJWnAoGBAJYb71ovzo71HK81vdCJZjxw
HGm5ZcvWyB63Yw3qmMhsHO48JOa9+rXqfOCxBd5HdPkDjqT23q0zMwJkOkexLaSt
KhO+8qBlo+9DERkadt3NAxUru+noZE0udAOaPXtP0nomvCAp1YmvnmLaZlzZPPYh
wDbzf0pjlLpJqe/29VqXAoGAbFVzTEE3S3jezjglu+7vufjHYFpzCY7jWv1Znibi
B471GPqEgzhmTcsfPkmo2vrUpkSWXsyVmlHars6r886eW3rmb5PWGA2fqf6trcSD
aI8amdqR0tHGiZ8kQgbUpA0zvfT8gAQqADrEvTCLcD+kqLcjKiqxqP7mXeK2HxLb
Dm8CgYEAn4ZA0ow12k0z3V7ZsQvHEKEquOIyuOYbfYoR2OEXTzbInPROwlWXtriG
G4Lp3Q4EhIvNN6TZhoCZ+/DGEMZ1XqTdIsj7IpJN6yLDu6IrENMuo9ZTybjZB20j
N56oNTN07p2fLLXT3b2UaxD1CYkXouSAXoxOBhfWlCAGFDJyJZ8=
-----END RSA PRIVATE KEY-----"#,
    };
    rsa_key
}


fn get_header() -> Header {

    let pub_key = get_rsa_key().pub_key;

    let mut hasher = Sha256::new();
    hasher.input_str(pub_key);
    let kid = hasher.result_str().to_uppercase();

    Header { alg: String::from("RS256"), kid }
}


#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct CustomClaims {
    appid: u32,         
    uty: String,          
    url_type: String,          
    isv_type: u8,         
    vsn: u8,          
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Payload {
    iss: String,
    sub: String,
    aud: String,
    iat: i64,
    exp: i64,
    custom_claims: CustomClaims,
}

pub fn new_token() {
    let privkey_pem = get_rsa_key().pri_key;

    let custom_claims = CustomClaims {
        appid: 100,         
        uty: String::from("email"),          
        url_type: String::from("0"),          
        isv_type: 0,         
        vsn: 1,  
    };

    let payload = Payload { 
        iss: String::from("www.italent.cn"),
        sub: String::from("admintest@szlanyou.com"),
        aud: String::from("430748"),
        iat: Utc::now().timestamp(),
        exp: Utc::now().add(Duration::seconds(10*60)).timestamp(),
        custom_claims,
    };

    let header = get_header();

    // 对header和payload进行分别json话之后进行base64加密
    let header_json = serde_json::to_string(&header).unwrap();
    let payload_json = serde_json::to_string(&payload).expect("error josn payload_json");

    println!("header: {:?}", header_json);
    println!("payload: {:?}", payload_json);

    let mut jwts = Vec::new();

    jwts.push(base64::encode(&header_json));
    jwts.push(base64::encode(&payload_json));

    let sign_content = format!("{}.{}", jwts.get(0).unwrap(), jwts.get(1).unwrap());

    println!("要签名的内容: {}", sign_content);

    let der_encoded = privkey_pem
        .lines()
        .filter(|line| !line.starts_with("-"))
        .fold(String::new(), |mut data, line| {
            data.push_str(&line);
            data
        });

    let der_bytes = base64::decode(&der_encoded).expect("erro get der_bytes");
    let private_key = RsaPrivateKey::from_pkcs1_der(&der_bytes).expect("error get private key");


    let mut hasher = Sha256::new();
    hasher.input_str(&sign_content);

    let mut buf: Vec<u8> = repeat(0).take((hasher.output_bits()+7)/8).collect();

    hasher.result(&mut buf);

    // 使用私钥签名
    let sign_result = private_key.sign(PaddingScheme::PKCS1v15Sign {hash: Some(Hash::SHA2_256) }, &mut buf).unwrap();

    let sign_result_64 = base64::encode(sign_result);

    jwts.push(sign_result_64);

    let j_h = jwts.get(0).unwrap().replace("+", "-").replace("/","_").replace("==", "");
    let j_p = jwts.get(1).unwrap().replace("+", "-").replace("/","_").replace("==", "");
    let j_s = jwts.get(2).unwrap().replace("+", "-").replace("/","_").replace("==", "");

    let token = format!("{}.{}.{}",j_h, j_p, j_s);

    println!("sign_result_64: https://oapi.italent.cn/SSO/AuthCenter?id_token={}", token);

}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn token() {
        new_token();
    }
}